Userinterface windows abstraction#345
Open
lexm2 wants to merge 17 commits into
Open
Conversation
Introduce IRawAccelDriver / IAccelEvaluator / ISystemDevicesRetriever behind the BackEnd, backed by the portable RawAccel.Contracts POCO project as the cross-OS JSON contract. Move the concrete Windows implementations (WindowsRawAccelDriver, ManagedAccelEvaluator, WindowsSystemDevicesRetriever) under Driver/Windows/. BackEndComposer registers the Windows impls; the curve preview and apply paths now talk to the interfaces. Windows-only: contains no Linux backend, agent, or cross-OS build scaffolding. The Linux HID-BPF implementation lands in a follow-up PR layered on top of this one.
…id-bpf Brings the backend hardening/cleanup and GUI work from userinterface-linux-hid-bpf onto the Windows abstraction branch, EXCLUDING the Linux driver implementations (userspace-backend/Driver/Linux/**). Faithful tree match of RawAccel.Contracts, userspace-backend, userspace-backend-tests, and userinterface to the hid-bpf branch, minus the 6 Linux driver files. Known dangling references to the excluded Linux classes (do not compile until reconciled): - userspace-backend/BackEndComposer.cs (Linux DI registration branch) - userspace-backend-tests/DisplayTests/CurvePreviewDisposalTests.cs
Make the transplanted backend compile without the excluded Linux driver
code (userspace-backend/Driver/Linux/**):
- BackEndComposer: drop the Linux DI registration branch; platform
switch is now Windows-or-throw (message updated to "Windows only").
- CurvePreviewDisposalTests: remove AccelInstance_DisposeIsIdempotent
(it instantiated LinuxAccelEvaluator); the 4 FakeEvaluator-based
disposal-contract tests still cover the regression.
The BackEndApplyTests compose the real backend graph and were designed to
run on Windows and Linux by injecting their own IRawAccelDriver +
ISystemDevicesRetriever before Compose. They relied on the platform branch
to supply IAccelEvaluator (the now-excluded LinuxAccelEvaluator), so they
broke once the Linux driver code was dropped.
- BackEndComposer: on non-Windows, register no platform defaults instead
of throwing; callers inject what they need and a missing service fails
at point of use, not at composition.
- BackEndApplyTests: add an identity FakeAccelEvaluator and register it
before each Compose so CurvePreview resolves without a platform driver.
70/70 backend tests pass on Linux; userspace-backend and userinterface build.
…ollisions
wrapper.vcxproj exposes Profile/AccelArgs/DeviceSettings/DeviceConfig/
AccelMode/CapMode/SpeedArgs as public C++/CLI types in the global
namespace. On Windows, where userspace-backend references the wrapper,
the using X = RawAccel.Contracts.RawAccelX; aliases introduced by the
Linux transplant collide with those global types (CS0576). Linux builds
weren't affected because wrapper isn't referenced there.
Prefix the aliases with Ra (RaProfile, RaAccelArgs, etc.) and update
in-file usages. Also:
- WindowsRawAccelDriver: DriverConfig.Deactivate is static, call it
directly instead of via GetDefault().
- userspace-backend-tests: qualify bare Profile/AccelMode references
that were silently resolving to the wrapper's globals.
Full solution now builds on Windows (driver.vcxproj still requires WDK).
userspace-backend-tests: 71/71 pass. wrapper-tests: 10/10 pass.
e6ae79e "Fix warnings" dropped the ex identifier from two catch (Exception) blocks but left the , ex inner-exception argument inside the rethrown ApplicationException, producing CS0103. Restore the variable name.
…speed line WindowsRawAccelDriver.GetCurrentMouseSpeedSample returned Zero, so the chart speed line never moved on Windows (unlike Linux, where the agent reports speed). Add RawInputMouseListener, which captures raw input (WM_INPUT) on its own message-only window and thread and reports the current speed in the chart units (counts/ms normalized to 1000 DPI). Per-device DPI normalization joins each WM_INPUT handle to its hardware-id via wrapper.dll MultiHandleDevice and looks up the applied config DPI, defaulting for unconfigured handles. The driver creates the listener lazily on first poll and disposes it via IDisposable.
Real fixes (not just cleanup): - ManagedAccelEvaluator: dispose the seed ManagedAccel after CreateStatelessCopy so its native instance pair frees deterministically instead of waiting on the finalizer. - RawInputMouseListener.UpdateDevices: per-device DPI fallback now uses the new config's default rather than the stale defaultDpi field. - RawInputMouseListener: bail (not silently continue) when RegisterRawInputDevices fails so running reflects reality. - RawInputMouseListener.FactorForHandle: drop the gate; handleFactors is volatile + build-once-publish so the WM_INPUT hot path is lock-free. - WindowsRawAccelDriver.Apply: don't fail Apply when only the post-apply listener.UpdateDevices throws (driver is already active); also IsNullOrEmpty for the wrapper errors string. - WindowsRawAccelDriver.Dispose: take listenerGate, flip a disposed flag, dispose outside the lock; closes a race where EnsureListener could resurrect a listener after Dispose nulled the field. Cleanups: - RawAccelConstants: add NormalizedDpi (mirrors common/rawaccel-base.hpp). - WindowsSystemDevice: capture name/HWID strings directly (??= empty) and drop the dead RawDevice ref-rooting field. - RawInputMouseListener: cache Marshal.SizeOf/OffsetOf results; drop the unused TranslateMessage call+import (message-only sink); upgrade setup failures to LogWarning and thread-loop catch to LogError; gate UnregisterClassW on a classRegistered flag; name LifecycleTimeoutMs; Volatile.Read/Write the cross-thread nativeThreadId. - WindowsRawAccelDriver: mark listener/lastConfig volatile for the EnsureListener fast-path and the Apply -> EnsureListener cross-thread read.
The Ra-prefixed Contracts aliases (RaProfile, RaAccelArgs, etc.) are a workaround for wrapper.cpp declaring its public C++/CLI types in the global namespace, which collides on Windows (CS0576). Note in the existing net8.0-migration TODO that namespacing the wrapper types is the real fix and should land with that migration.
Comment blocks across the backend had been padded so every line landed at roughly the same column, which left filler words behind. Strip the padding and collapse the longest blocks (the wrapper-migration TODOs, the ProfilesModel circular-dep TODO, several XML doc <remarks>) without losing substance or test/file references.
…idator Profile names were validated only for length/non-emptiness, so two profiles could share a name (unlike mappings). Add ProfileNameValidator mirroring MappingNameValidator: it checks case-insensitive uniqueness via IProfilesModel.TryGetProfile plus the prior non-empty/max-length guard, and register it as the keyed validator for the profile Name setting. No DI cycle exists despite the removed TODO's premise: ProfilesModel's ctor builds no ProfileModel instances, so the validator's IProfilesModel dependency resolves against the already-built singleton.
State the shared mirror/JSON-contract rule once on RawAccelConfig instead of repeating it (plus its 'do not rename' elaboration) on every type; reduce the rest to a one-line wrapper.cpp pointer. Replace the version comment with a TODO to unify version bumps (1.7.1 vs driver-still-1.7.0 mismatch).
Collapse multi-line/padded comments (and the ====-banner dividers unique to ProfileChartViewModel) down to terse 1-3 line notes, matching the single-line comment style used across the rest of the codebase. Drop the repeated "reassign fresh Sections so LiveCharts redraws" rationale to a single statement on the Sections property. No behavior change.
Default values for acceleration-formula settings were defined twice: as the EditableSetting initial values in BackEndComposer DI registration, and as auto-property initializers in the Data DTOs (only NaturalAccel had these). Add a single FormulaDefaults const class referenced by both. The five DTOs that previously lacked initializers now fall back to the proper default instead of 0 when a field is absent from partial JSON; fully-written profiles are unaffected. FormulaDefaults is intentionally independent of native/Contracts.
… types Adds Classic and Linear DataRows to DeserializeFormulaAccel_AllSubtypes so the parameterized test covers every formula type, and trims the three-line regression comment to one line.
Restore original comment wording in ProfileChartViewModel, Program, App.axaml, BackEndApplyTests, EditableSetting, EditableSettingsCollection, EditableSettingsSelector, IEditableSetting, ProfileModel, and SystemDevices. Also extend .gitignore to cover linux/build-*/, linux/target/, and Testing/ so CMake/Rust build artifacts are never staged again.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This refactors the userspace backend so it talks to the driver through a platform abstraction instead of directly against the Windows C++/CLI wrapper. Driver access and acceleration evaluation now live behind interfaces, with Windows as the first concrete implementation, and a new
RawAccel.Contractsproject holds the OS independent data shapes both sides share. The goal is to make the backend portable so a non-Windows (Linux) backend can plug in later.What changed
Driver abstraction. Adds
IRawAccelDriverandIAccelEvaluator, and moves all the Windows specific code underDriver/Windows/(WindowsRawAccelDriver,ManagedAccelEvaluator,RawInputMouseListener,WindowsSystemDevicesRetriever).RawAccel.Contracts. New project with OS independent config/profile types (
RawAccelConfig,RawAccelProfile,RawAccelDeviceConfig,RawAccelAccelArgs,RawAccelSpeedArgs,Vec2, plus shared enums and constants), decoupling the backend and tests from the native struct layout.Backend cleanup.
BackEndComposeris heavily simplified, formula defaults are unified into a singleFormulaDefaults, and profile name uniqueness is now enforced through a validator.Live speed line. Mouse speed is captured live on Windows (
RawInputMouseListener+MouseSpeedPollingService) to drive the current-speed line on the chart.Testing
Backend test coverage was expanded and made to pass on non Windows, adding round trip, validation, and curve-preview disposal tests.